package de.plushnikov.intellij.plugin.processor;

import com.ecode.annotation.EcodeDo;
import com.ecode.annotation.core.DefaultErrorCoderBuilder;
import com.ecode.annotation.enums.CodeDataFromEnum;
import com.ecode.annotation.enums.CodeDataTypeEnum;
import com.ecode.annotation.model.ErrorCodeDO;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.javadoc.PsiDocCommentImpl;
import de.plushnikov.intellij.plugin.LombokBundle;
import de.plushnikov.intellij.plugin.LombokClassNames;
import de.plushnikov.intellij.plugin.problem.ProblemBuilder;
import de.plushnikov.intellij.plugin.processor.clazz.AbstractClassProcessor;
import de.plushnikov.intellij.plugin.psi.LombokEnumConstantBuilder;
import de.plushnikov.intellij.plugin.util.LombokProcessorUtil;
import de.plushnikov.intellij.plugin.util.PsiAnnotationUtil;
import okhttp3.OkHttp;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

public class ECodeProcessor extends AbstractClassProcessor {

  public ECodeProcessor() {
    super(PsiField.class, LombokClassNames.ECODE);
  }

  @Override
  protected boolean validate(@NotNull PsiAnnotation psiAnnotation, @NotNull PsiClass psiClass, @NotNull ProblemBuilder builder) {
    return validateAnnotationOnRightType(psiAnnotation, psiClass, builder) && validateVisibility(psiAnnotation);
  }

  @Override
  protected void generatePsiElements(@NotNull PsiClass psiClass, @NotNull PsiAnnotation psiAnnotation, @NotNull List<? super PsiElement> target) {
    final String methodVisibility = LombokProcessorUtil.getAccessVisibility(psiAnnotation);
    if (methodVisibility != null) {
      target.addAll(createFieldSetters(psiClass));
    }
  }

  @Override
  public boolean notNameHintIsEqualToSupportedAnnotation(@Nullable String nameHint) {
    return super.notNameHintIsEqualToSupportedAnnotation(nameHint);
  }

  @Override
  public @NotNull List<? super PsiElement> process(@NotNull PsiClass psiClass) {
    return super.process(psiClass);
  }

  private boolean validateAnnotationOnRightType(@NotNull PsiAnnotation psiAnnotation, @NotNull PsiClass psiClass, @NotNull ProblemBuilder builder) {
//    PsiField[] fields = psiClass.getFields();
//    for (PsiField field : fields) {
//      if("DEFAULT_ERROR_CODE".equals(field.getName())){
//        System.out.println(field.getName());
//        System.out.println(field.getType());
//        System.out.println(field.getClass().getName());
//        PsiEnumConstantImpl psiEnumConstant = (PsiEnumConstantImpl) field;
//        System.out.println("getInitializer: " + psiEnumConstant.getInitializer());
//        System.out.println("getStub" + psiEnumConstant.getStub());
//        System.out.println("node" + psiEnumConstant.getNode());
//        EnumConstantElement nod = (EnumConstantElement) psiEnumConstant.getNode();
//        System.out.println("ASTNODE : " +  psiEnumConstant.getNode().getClass().getName());
//        System.out.println("firstChild " + psiEnumConstant.getNode().getFirstChildNode());
//        System.out.println("firstChildClassName " + psiEnumConstant.getNode().getFirstChildNode().getClass());
//        System.out.println("text" + psiEnumConstant.getNode().getFirstChildNode().getText());
//
//        System.out.println("____________");
//        System.out.println(psiEnumConstant.getStub());
//
//        ModifierListElement modifierListElement = (ModifierListElement) psiEnumConstant.getNode().getFirstChildNode();
//        System.out.println("keyMap : " + modifierListElement.get());
//        System.out.println("tezxt" + modifierListElement.getText());
//        System.out.println("psi:" + modifierListElement.getPsi());
//        System.out.println("getUserDataString:" + modifierListElement.getUserDataString());
//        System.out.println("getChars:" + modifierListElement.getChars());
//      }
//    }
    boolean result = true;
    //验证，只支持枚举类型
    if (!psiClass.isEnum()) {
      builder.addError(LombokBundle.message("inspection.message.s.only.supported.on.class.or.field.type"), psiAnnotation.getQualifiedName());
      result = false;
    }
    return result;
  }

  private boolean validateVisibility(@NotNull PsiAnnotation psiAnnotation) {
    return true;
  }

  public Collection<PsiElement> createFieldSetters(@NotNull PsiClass psiClass) {
    final Collection<PsiElement> eCodeFields = createECodeField(psiClass);
    return eCodeFields;
  }


  @NotNull
  private Collection<PsiElement> createECodeField(@NotNull PsiClass psiClass) {

    final Collection<PsiElement> eCodeFields = new ArrayList<>();
    PsiAnnotation psiAnnotation = psiClass.getAnnotation("com.ecode.annotation.ErrorCode");

    EcodeDo ecodeDo = new EcodeDo();
    ecodeDo.setDataType(CodeDataTypeEnum.valueOf(PsiAnnotationUtil.getEnumAnnotationValue(psiAnnotation, "dataType", "JSON")));
    ecodeDo.setDataFROM(CodeDataFromEnum.valueOf(PsiAnnotationUtil.getEnumAnnotationValue(psiAnnotation, "dataFROM", "MYSQL")));
    ecodeDo.setMysqlUrl(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "mysqlUrl", ""));
    ecodeDo.setMysqlTableName(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "mysqlTableName", ""));
    ecodeDo.setMysqlUserName(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "mysqlUserName", ""));
    ecodeDo.setMysqlUserPass(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "mysqlUserPass", ""));
    ecodeDo.setProjectConfigPath(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "projectConfigPath", ""));
    ecodeDo.setLocalPath(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "localPath", ""));
    ecodeDo.setConfigUrl(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "configUrl", ""));
    ecodeDo.setOtherConfig(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "otherConfig", ""));
    ecodeDo.setCustomDataPullBuilder(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "customDataPullBuilder", ""));
    ecodeDo.setCustomDataParseClass(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "customDataParseClass", ""));
    ecodeDo.setSys(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "sys", ""));
    ecodeDo.setModel(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "model", ""));
    ecodeDo.setVersion(PsiAnnotationUtil.getStringAnnotationValue(psiAnnotation, "version", ""));

    DefaultErrorCoderBuilder builder = new DefaultErrorCoderBuilder();
    Set<ErrorCodeDO> errorCodes = builder.parseErrorCode(ecodeDo);
    final Project project = psiClass.getProject();

    final PsiElementFactory psiElementFactory = JavaPsiFacade.getElementFactory(project);
    PsiType psiType = psiElementFactory.createType(psiClass);

    String eCodeFormat = "%s(%s, %s)";

    for (ErrorCodeDO errorCodeDO : errorCodes) {
      LombokEnumConstantBuilder psiEnumConstant = new LombokEnumConstantBuilder(psiClass.getManager(), errorCodeDO.buildCode(), psiType);
      String initiazer = String.format(eCodeFormat, psiClass.getName(), errorCodeDO.buildCode(), errorCodeDO.getMsg());
      PsiExpression psiExpression = psiElementFactory.createExpressionFromText(initiazer, psiClass);
      psiEnumConstant.setInitializer(psiExpression);

      psiEnumConstant.setDocComment(new PsiDocCommentImpl(errorCodeDO.getMsg()));
      psiEnumConstant.withModifier(PsiModifier.FINAL);
      psiEnumConstant.withModifier(PsiModifier.PUBLIC);
      psiEnumConstant.withModifier(PsiModifier.STATIC);
      psiEnumConstant.withNavigationElement(psiAnnotation);

      eCodeFields.add(psiEnumConstant);
    }
    System.out.println(eCodeFields);
    return eCodeFields;
  }
}
